package graduation.claf.service;

import graduation.claf.dao.BookMapper;
import graduation.claf.dao.OwnershipMapper;
import graduation.claf.dao.RecordMapper;
import graduation.claf.pojo.Record;
import graduation.claf.service.ifs.IRecordService;
import graduation.claf.tools.ResponseCode;
import graduation.claf.utils.ServerResponse;
import graduation.claf.vo.ClassifiedInfo;
import graduation.claf.vo.FlowStatistic;
import graduation.claf.vo.StatisticInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

import static graduation.claf.tools.Tool.createUUID;

@Service
public class RecordService implements IRecordService {

    @Autowired
    OwnershipMapper ownershipMapper;
    @Autowired
    RecordMapper recordMapper;
    @Autowired
    BookMapper bookMapper;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public ServerResponse AddRecord(Record record) {
        record.setRecordid(createUUID());
        if (ownershipMapper.IsMembers(record.getBookid(),record.getUserid()) == 0)
            return ServerResponse.createServerResponseByFail(
                    ResponseCode.USER_NOT_MEMBERS.getCode(),
                    ResponseCode.USER_NOT_MEMBERS.getMsg());
        if (recordMapper.insert(record) != 0) {
            if (record.getType() == 0) {
                double budget = bookMapper.getBudget(record.getBookid());
                if (budget == -1) {
                    return ServerResponse.createServerResponseBySuccess(
                            ResponseCode.INSERT_SUCCESS.getCode(),
                            ResponseCode.INSERT_SUCCESS.getMsg());
                } else {
                    Calendar start = Calendar.getInstance();
                    Calendar end = Calendar.getInstance();
                    constructIntervalOfDate(start,end,2);
                    double income = recordMapper.OutcomeStatistic(record.getBookid(),sdf.format(start.getTime()),sdf.format(end.getTime()));
                    System.out.println(income);
                    if (budget*0.8<income){
                        return ServerResponse.createServerResponseByFail(
                                ResponseCode.BUDGET_OVERRUN.getCode(),
                                income,
                                ResponseCode.BUDGET_OVERRUN.getMsg());
                    } else {
                        return ServerResponse.createServerResponseBySuccess(
                                ResponseCode.INSERT_SUCCESS.getCode(),
                                ResponseCode.INSERT_SUCCESS.getMsg());
                    }
                }
            } else {
                return ServerResponse.createServerResponseBySuccess(
                        ResponseCode.INSERT_SUCCESS.getCode(),
                        ResponseCode.INSERT_SUCCESS.getMsg());
            }
        }
        return ServerResponse.createServerResponseByFail(
                ResponseCode.INSERT_FAIL.getCode(),
                ResponseCode.INSERT_FAIL.getMsg());
    }

    @Override
    public StatisticInfo SumStatistic(String bookId,int type) {
        StatisticInfo statisticInfo = StatisticInfo.createStatistic(type);
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
        if (!constructIntervalOfDate(start,end,type)){
            return null;
        }
        double income = 0;
        double outcome = 0;
        income = recordMapper.IncomeStatistic(bookId, sdf.format(start.getTime()), sdf.format(end.getTime()));
        outcome = recordMapper.OutcomeStatistic(bookId, sdf.format(start.getTime()), sdf.format(end.getTime()));
        statisticInfo.setIncome(income);
        statisticInfo.setOutcome(outcome);
        statisticInfo.setRemark(sdf2.format(start.getTime())+"_"+sdf2.format(end.getTime()));
        return statisticInfo;
    }

    @Override
    public List<Record> Details(String bookId, Calendar start, Calendar end) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Record> records = recordMapper.searchRecordsByDate(bookId, sdf.format(start.getTime()), sdf.format(end.getTime()));
        return records;
    }

    public boolean constructIntervalOfDate(Calendar start,Calendar end,int timeZoneType){
        start.set(Calendar.HOUR_OF_DAY,0);
        start.set(Calendar.MINUTE,0);
        start.set(Calendar.SECOND,0);
        end.set(Calendar.HOUR_OF_DAY,23);
        end.set(Calendar.MINUTE,59);
        end.set(Calendar.SECOND,59);
        Calendar today = Calendar.getInstance();
        int year = today.get(Calendar.YEAR);
        int month = today.get(Calendar.MONTH);
        int day = today.get(Calendar.DATE);
        switch (timeZoneType){
            case 0:
                //当日
                start.set(year, month, day);
                end.set(year, month, day);
                return true;
            case 1:
                //本周
                getWeekStart(start);
                getWeekEnd(end);
                return true;
            case 2:
                //本月
                start.set(year,month,1);
                end.set(Calendar.DATE, 1);
                end.roll(Calendar.DATE, -1);
                return true;
            case 3:
                //今年
                start.set(year,0,1);
                end.set(year,11,31);
                return true;
            default:
                return false;
        }
    }

    @Override
    public ServerResponse classifiedStatistic(String bookId, int timeZoneType) {
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        if (!constructIntervalOfDate(start,end,timeZoneType)){
            return ServerResponse.createServerResponseByFail(ResponseCode.PARAMETER_ERROR.getCode(),
                    ResponseCode.PARAMETER_ERROR.getMsg());
        }
        List<Record> records = Details(bookId,start,end);
        if (records == null) return ServerResponse.createServerResponseByFail(ResponseCode.RECORD_NOT_EXISTS.getCode(),ResponseCode.RECORD_NOT_EXISTS.getMsg());
        Hashtable<String, Double> inHashTable = new Hashtable<>();
        Hashtable<String, Double> outHashTable = new Hashtable<>();
        for (Record record : records){
            if (record.getType() == 0)
                addToHashTable(outHashTable,record.getFirstclass(),record.getMoney());
            else
                addToHashTable(inHashTable,record.getFirstclass(),record.getMoney());
        }
        ClassifiedInfo information = new ClassifiedInfo(inHashTable,outHashTable);
        return ServerResponse.createServerResponseBySuccess(information);
    }

    public void addToHashTable(Hashtable<String ,Double> hashtable,
                               String classification,Double amount){
        if (hashtable.containsKey(classification)){
            amount = hashtable.get(classification)+amount;
        }
        hashtable.put(classification, amount);
    }

    @Override
    public ServerResponse flowStatistic(String bookId, int timeZoneType) {
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        Calendar today = Calendar.getInstance();
        List<FlowStatistic> flows = new ArrayList<>();
        long times = 0;
        if (!constructIntervalOfDate(start,end,timeZoneType)){
            return ServerResponse.createServerResponseByFail(ResponseCode.PARAMETER_ERROR.getCode(),
                    ResponseCode.PARAMETER_ERROR.getMsg());
        }
        switch (timeZoneType){
            case 0:
                //今天
                flows.add(searchFlowsByZone(bookId,start,end,0,null));
                break;
            case 1:
                //本周
                times = (today.getTimeInMillis()-start.getTimeInMillis())/(1000 * 60 * 60 * 24);
                System.out.println(sdf.format(start.getTime()));
                System.out.println(sdf.format(end.getTime()));
                System.out.println(sdf.format(today.getTime()));
                System.out.println(times);
                flows = searchFlowsByWeek(bookId,start,(int)times + 1);
                break;
            case 2:
                //本月
                flows = searchFlowsByMonth(bookId,2);
                break;
            case 3:
                //今年
                times = today.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 1;
                flows = searchFlowsByYear(bookId,start,(int)times);
                break;
        }
        return ServerResponse.createServerResponseBySuccess(flows);
    }

    public FlowStatistic searchFlowsByZone(String bookId, Calendar start, Calendar end,int type,String remark){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        List<Record> records;
        StatisticInfo statisticInfo = new StatisticInfo();
        statisticInfo.setName(sdf1.format(start.getTime()));
        statisticInfo.setType(type);
        statisticInfo.setRemark("0");
        statisticInfo.setIncome(recordMapper.IncomeStatistic(bookId,sdf.format(start.getTime()),sdf.format(end.getTime())));
        statisticInfo.setOutcome(recordMapper.OutcomeStatistic(bookId,sdf.format(start.getTime()),sdf.format(end.getTime())));
        if ((statisticInfo.getIncome()==0)&&(statisticInfo.getOutcome()==0)){
            statisticInfo.setRemark("-1");  //暂无消费记录
            records = null;
        }else {
            records = recordMapper.searchRecordsByDate(bookId, sdf.format(start.getTime()), sdf.format(end.getTime()));
        }
        if (remark!=null){
            statisticInfo.setRemark(remark);
        }
        return new FlowStatistic(statisticInfo,records);
    }

    public List<FlowStatistic> searchFlowsByWeek(String bookId, Calendar start, int times){
        Calendar end = Calendar.getInstance();
        end.setTime(start.getTime());
        end.set(Calendar.HOUR_OF_DAY,23);
        end.set(Calendar.MINUTE,59);
        end.set(Calendar.SECOND,59);
        List<FlowStatistic> tempFlows = new ArrayList<>();
        for (int i = 0; i<times ;i++){
            FlowStatistic flow = searchFlowsByZone(bookId,start,end,1,null);
            if (flow!=null) tempFlows.add(flow);
            start.add(Calendar.DATE,1);
            end.add(Calendar.DATE,1);
        }
        Collections.reverse(tempFlows);
        return tempFlows;
    }

    public List<FlowStatistic> searchFlowsByMonth(String bookId,int type){
        int count = 0;
        Calendar today = Calendar.getInstance();
        //Calendar today = new GregorianCalendar(2020,3,29,11,7,23);
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        List<FlowStatistic> flows = new ArrayList<>();
        constructIntervalOfDate(start,end,1);

        if (today.getTimeInMillis() < end.getTimeInMillis())
            end.set(Calendar.DATE,today.get(Calendar.DATE));

        while (true){
            if (start.get(Calendar.MONTH) != today.get(Calendar.MONTH)){
                start.set(Calendar.MONTH, today.get(Calendar.MONTH));
                start.set(Calendar.DATE, 1);
                flows.add(searchFlowsByZone(bookId,start,end,type,(count++)+""));
                break;
            }else{
                flows.add(searchFlowsByZone(bookId,start,end,type,(count++)+""));
                start.add(Calendar.DATE,-7);
                end.setTime(start.getTime());
                end.add(Calendar.DATE,6);
                end.set(Calendar.HOUR_OF_DAY,23);
                end.set(Calendar.MINUTE,59);
                end.set(Calendar.SECOND,59);
            }
        }
        return flows;
    }

    public List<FlowStatistic> searchFlowsByYear(String bookId,Calendar start,int times){
        Calendar end = Calendar.getInstance();
        end.set(Calendar.HOUR_OF_DAY,23);
        end.set(Calendar.MINUTE,59);
        end.set(Calendar.SECOND,59);
        setLastDayOfMonth(start,end);
        List<FlowStatistic> tempFlows = new ArrayList<>();
        for (int i = 0; i<times ;i++){
            FlowStatistic temp = searchFlowsByZone(bookId,start,end,3,null);
            if (temp != null) tempFlows.add(temp);
            start.add(Calendar.MONTH,1);
            setLastDayOfMonth(start,end);
        }
        Collections.reverse(tempFlows);
        return tempFlows;
    }

    public void setLastDayOfMonth(Calendar start,Calendar end){
        end.setTime(start.getTime());
        end.set(Calendar.DATE, 1);
        end.roll(Calendar.DATE, -1);
    }

    public void getWeekStart(Calendar calendar){
        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (day_of_week == 0) day_of_week = 7;
        calendar.add(Calendar.DATE, -day_of_week + 1);
    }

    public void getWeekEnd(Calendar calendar){
        int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (day_of_week == 0)
            day_of_week = 7;
        calendar.add(Calendar.DATE, -day_of_week + 7);
    }

    @Override
    public ServerResponse modifyWithId(Record record) {
        if (recordMapper.updateByPrimaryKey(record)==0)
            return ServerResponse.createServerResponseByFail(
                    ResponseCode.UPDATE_FAIL.getCode(),
                    ResponseCode.UPDATE_FAIL.getMsg());
        return ServerResponse.createServerResponseBySuccess();
    }

    @Override
    public ServerResponse deleteWithId(String recordId) {
        if (recordMapper.deleteByPrimaryKey(recordId) == 0){
            return ServerResponse.createServerResponseByFail(
                    ResponseCode.DELETE_FAIL.getCode(),
                    ResponseCode.DELETE_FAIL.getMsg());
        }
        return ServerResponse.createServerResponseBySuccess();
    }

    @Override
    public ServerResponse searchRecords(String bookId, int timeZone) {
        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        constructIntervalOfDate(start,end,timeZone);
        List<Record> records;
        records = Details(bookId,start,end);
        return ServerResponse.createServerResponseBySuccess(records);
    }
}
